/*
对Function对象的扩展，最令人激动的部分，JS框架必不可少的部分
由于JS中只有函数是安全的作用域(with不可靠)，所以优雅的JS OOP有赖于此
只是有一点，不知道moo为什么不实现函数的柯里化，而Prototype中有相应实现
*/

Function.implement({


 //扩展方法，moo中很多对象都有同名方法的实现
 extend: function(properties){

  for (var property in properties) this[property] = properties[property];

  return this;

 },


 //创建新函数，功能最强的实现，后面的其它扩展都依赖于它的实现

 create: function(options){
  
  //将上下文对象指向一个临时变量，以便在闭包中使用
  var self = this;

  //又见||的写法

  options = options || {};
  
  //返回一个闭包，其中event参数主要用于非IE浏览器中事件对象的引用

  return function(event){

   //同样，用于闭包使用的变量

   var args = options.arguments;

   args = $defined(args) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
   
   /*
   是否需要捕获事件
对象，可以看到仍然将事件对象作为第一个参数
   因此在使用bindWithEvent时，需要记你的方法/函数的第一个参数是事件
   */
   if (options.event) args = [event || window.event].extend(args);
   
   //闭包中的闭包

   var returns = function(){

    return self.apply(options.bind || null, args);

   };
   
   //指定延迟执行函数

   if (options.delay) return setTimeout(returns, options.delay);
   
   //指定周期性执行函数

   if (options.periodical) return setInterval(returns, options.periodical);
   
   //指定尝试执行函数，用$try忽略错误

   if (options.attempt) return $try(returns);
   

   return returns();

  };

 },


 
 //制造一个已提供所需要参数的函数，之后再执行时就不必再传参数

 pass: function(args, bind){

  return this.create({arguments: args, bind: bind});

 },

 

 //尝试执行函数而忽略错误信息

 attempt: function(args, bind){

  return this.create({arguments: args, bind: bind, attempt: true})();

 },

 

 //在旧函数基础上绑定指向函数内this的新函数
 bind: function(bind, args){

  return this.create({bind: bind, arguments: args});

 },

 

 //创建一个绑定事件对象的函数

 bindWithEvent: function(bind, args){

  return this.create({bind: bind, event: true, arguments: args});

 },

 

 //延时执行函数，注意参数的顺序和对应的意义

 delay: function(delay, bind, args){

  return this.create({delay: delay, bind: bind, arguments: args})();

 },

 

 //周期性执行函数，注意参数的顺序和对应的意义

 periodical: function(interval, bind, args){

  return this.create({periodical: interval, bind: bind, arguments: args})();

 },

 //柯里化，我自己所加，非moo内置

 curry: function() {
  if (!arguments.length) return this;
  var self = this, args = $A(arguments);
  return function() {
    return self.apply(this, args.extend($A(arguments)));
  }
 },


 //直接执行函数，和直接加()执行相比，可提供改变this的对象

 run: function(args, bind){

  return this.apply(bind, $splat(args));

 }

 

});